/****************************************************************************
 * 
 * FILENAME
 *     W99702_WM8978.c
 *
 * VERSION
 *     0.1 
 *
 * DESCRIPTION
 *
 *
 *
 *
 * DATA STRUCTURES
 *     None
 *
 * FUNCTIONS
 *
 *
 *     
 * HISTORY
 *     2004.07.16		Created by Shih-Jen Lu
 *
 *
 * REMARK
 *     None
 *
 *
 **************************************************************************/
#ifdef ECOS
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "drv_api.h"
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif

#include "wbio.h"
#include "NUC900_AUDIO.h"
#include "NUC900_Audio_Regs.h"
#include "NUC900_i2c.h"
#include "IIS.h"

#define	WM_8000		(5<<1)
#define	WM_12000	(4<<1)
#define	WM_16000	(3<<1)
#define	WM_24000	(2<<1)	
#define	WM_32000	(1<<1)
#define	WM_48000	0
           
#define	WM_11025	(4<<1)
#define	WM_22050	(2<<1)
#define	WM_44100	0

INT uSamplingRate = AU_SAMPLE_RATE_44100;

void WM8978_Init(void)
{
	_debug_msg("init wm8978-i2c\n");
	i2cInit();
	i2cOpen(0);	//open i2c channel 0 for wm8978	
	i2cIoctl(0, I2C_IOC_SET_DEV_ADDRESS, 0x1A, 0); 
	i2cIoctl(0, I2C_IOC_SET_SPEED, 100, 0);
}

void WM8978_WriteData(char addr, unsigned short data)
{
	UINT8 i2cdata[2];
	INT j;
	
	i2cdata[0] = ((addr << 1)  | (data >> 8));		//addr(7bit) + data(first bit)
	i2cdata[1] = (char)(data & 0x00FF);			//data(8bit)
	
	i2cIoctl(0, I2C_IOC_SET_SUB_ADDRESS, i2cdata[0], 1);	
	j = 10;	
	while(j-- > 0) 
	{
		if(i2cWrite(0, &i2cdata[1], 1) == 1)
			break;
	}							
}

static void Delay(int nCnt)
{
	volatile int  loop;
	for (loop=0; loop<nCnt*10; loop++);
}

/*---------- for WM8978	functions group----------*/
//(MIN)  0 ~ (MAX) 255
int WM8978_Set_DAC_Volume(UINT8 ucLeftVol, UINT8 ucRightVol)
{	//0~31

	/* R11 DACOUTL R12 DACOUTR, R52 HPOUTL R53 HPOUTR, R54 SPOUTL R55 SPOUTR */
	UINT16 data;
	if (ucLeftVol!=0)
		data = (1<<8) | (ucLeftVol*3 + 130);
	else
		data = (1<<8);
	WM8978_WriteData(11, data);
		
	if (ucRightVol!=0)
		data = (1<<8) | (ucRightVol*3 + 130);
	else
		data = (1<<8);
	WM8978_WriteData(12, data);
	
//HeadPhone
	if (ucLeftVol!=0)	//0~127
		data = (1<<8) | (ucLeftVol + 32);
	else
		data = (1<<8);
	WM8978_WriteData(52, data);
		
	if (ucRightVol!=0)
		data = (1<<8) | (ucRightVol + 32);
	else
		data = (1<<8);
	WM8978_WriteData(53, data);
	
//Speaker	
	if (ucLeftVol!=0)
		data = (1<<8) | (ucLeftVol + 32);
	else
		data = (1<<8);
	WM8978_WriteData(54, data);
		
	if (ucRightVol!=0)
		data = (1<<8) | (ucRightVol + 32);
	else
		data = (1<<8);
		
	WM8978_WriteData(55, data);
	return 0;
}	

int WM8978_Set_ADC_Volume(UINT8 ucLeftVol, UINT8 ucRightVol)
{
	UINT16 data;
	
	if (ucLeftVol<=8)
		data = 0x100 | ucLeftVol;
	else if (ucLeftVol<=16&&ucLeftVol>8)
		data = 0x100 | ucLeftVol * 4;
	else if (ucLeftVol<=31&&ucLeftVol>16)
		data = 0x100 | ucLeftVol * 8;
	WM8978_WriteData(15, data);
			
	if (ucRightVol<=8)
		data = 0x100 | ucRightVol;
	else if (ucRightVol<=16&&ucRightVol>8)
		data = 0x100 | ucRightVol * 4;
	else if (ucRightVol<=31&&ucRightVol>16)
		data = 0x100 | (ucRightVol * 8 + 7);	
	
	WM8978_WriteData(16, data);
	return 0;
}

void WM8978_Set_Sample_Frequency(INT uSample_Rate)
{
	UINT16 data=0;
	
	_debug_msg("Set sample rate\n");
	switch (uSample_Rate)
	{
		case AU_SAMPLE_RATE_8000:							//8KHz
			data = WM_8000 ;
			break;
		case AU_SAMPLE_RATE_11025:					//11.025KHz
			data = WM_11025 ;

			break;
		case AU_SAMPLE_RATE_16000:						//16KHz
			data = WM_16000 ;

			break;
		case AU_SAMPLE_RATE_22050:					//22.05KHz
			data = WM_22050;

			break;
		case AU_SAMPLE_RATE_24000:						//24KHz
			data = WM_24000;

			break;
		case AU_SAMPLE_RATE_32000:						//32KHz
			data = WM_32000 ;

			break;
		case AU_SAMPLE_RATE_44100:					//44.1KHz
			data = WM_44100 ;

			break;
		case AU_SAMPLE_RATE_48000:						//48KHz
			data = WM_48000;

			break;
		default:break;
	}
	
	WM8978_WriteData(7,data|1); 		
}
	
void WM8978_DAC_Setup(void)
{
	_debug_msg("DAC\n");
	WM8978_WriteData(0, 0x000);
	Delay(0x100);
	WM8978_WriteData(1, 0x01F);//R1 OUT4MIXEN OUT3MIXEN MICBEN BIASEN BUFIOEN VMIDSEL
	WM8978_WriteData(2, 0x1BF);//R2 power up ROUT1 LOUT1 
	WM8978_WriteData(3, 0x06F);//R3 OUT4EN OUT3EN SPKNEN SPKPEN RMIXEN LMIXEN DACENR DACENL		
	WM8978_WriteData(4, 0x010);//R4 select audio format(I2S format) and word length (16bits)
	WM8978_WriteData(5, 0x000);//R5 companding ctrl and loop back mode (all disable)
	WM8978_WriteData(6, 0x000);//R6 clock Gen ctrl(slave mode)
	WM8978_WriteData(10, 0x008);//R10 DAC control (softmute disable, oversample select 64x (lowest power) )
	WM8978_WriteData(43, 0x010);//For differential speaker
	WM8978_WriteData(45, 0x139);//R10 DAC control (softmute disable, oversample select 64x (lowest power) )
	WM8978_WriteData(50, 0x001);//R50 DACL2LMIX
	WM8978_WriteData(51, 0x001);//R51 DACR2RMIX
	WM8978_WriteData(49, 0x002);
	WM8978_WriteData(54, 0x139);//For differential speaker
	
	WM8978_Set_Sample_Frequency(uSamplingRate);//R7 set sampling rate
}

void WM8978_ADC_Setup(void)
{
	_debug_msg("ADC\n");
	WM8978_WriteData(0, 0x000);
	Delay(0x100);
	WM8978_WriteData(1, 0x01F);//R1 MICBEN BIASEN BUFIOEN VMIDSEL
	WM8978_WriteData(2, 0x03F);//R2 power up ROUT1 LOUT1 
	WM8978_WriteData(4, 0x010);//R4 select audio format(I2S format) and word length (16bits)
	WM8978_WriteData(5, 0x000);//R5 companding ctrl and loop back mode (all disable)
	WM8978_WriteData(6, 0x000);//R6 clock Gen ctrl(slave mode)
	
	WM8978_Set_Sample_Frequency(uSamplingRate);//R7 set sampling rate
}
	

/*---------- end of WM8978's functions group ----------*/

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      wm8978SetPlayVolume                                                 */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Set i2S left and right channel play volume.                      */
/*                                                                       */
/* INPUTS                                                                */
/*      ucLeftVol    play volume of left channel                         */
/*      ucRightVol   play volume of left channel                         */
/*                  0:  mute                                             */
/*                  1:  minimal volume                                   */
/*                  31: maxmum volume                                    */
/*                                                                       */
/* OUTPUTS                                                               */
/*      None                                                             */
/*                                                                       */
/* RETURN                                                                */
/*      0           Success                                              */
/*		Otherwise	error												 */
/*                                                                       */
/*************************************************************************/
INT  wm8978SetPlayVolume(UINT8 ucLeftVol, UINT8 ucRightVol)  //0~31
{
	if (ucLeftVol>31)
		ucLeftVol=31;
	if (ucRightVol>31)
		ucRightVol=31;
	
	WM8978_Set_DAC_Volume(ucLeftVol,ucRightVol);

	return 0;
}

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      wm8978SetRecordVolume                                                 */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Set i2S left and right channel record volume.                      */
/*                                                                       */
/* INPUTS                                                                */
/*      ucLeftVol    record volume of left channel                         */
/*      ucRightVol   record volume of left channel                         */
/*                  0:  mute                                             */
/*                  1:  minimal volume                                   */
/*                  31: maxmum volume                                    */
/*                                                                       */
/* OUTPUTS                                                               */
/*      None                                                             */
/*                                                                       */
/* RETURN                                                                */
/*      0           Success                                              */
/*		Otherwise	error												 */
/*                                                                       */
/*************************************************************************/
INT  wm8978SetRecordVolume(UINT8 ucLeftVol, UINT8 ucRightVol)  //0~31
{	
	if (ucLeftVol>31)
		ucLeftVol=31;
	if (ucRightVol>31)
		ucRightVol=31;

	WM8978_Set_ADC_Volume(ucLeftVol,ucRightVol);
  	
	return 0;
}
